#include "spi_driver.hpp"
#include "driver/gpio.h"
#include "esp_log.h"
#include <cstring>

#define TAG "SPI_DRIVER"
#define SPI_DEFAULT_FREQUENCY 1000000 // 1MHz
SPIDriver::SPIDriver()
    : m_clock_speed_hz(SPI_DEFAULT_FREQUENCY), m_spi_host(SPI2_HOST)
{
    // Default constructor, no initialization needed
}

SPIDriver::SPIDriver(int mosi, int miso, int sclk, spi_host_device_t spi_host)
    : m_clock_speed_hz(SPI_DEFAULT_FREQUENCY), m_spi_host(SPI2_HOST)
{
    init(mosi, miso, sclk, spi_host);
}

void SPIDriver::init(int mosi, int miso, int sclk, spi_host_device_t spi_host)
{
    spi_bus_config_t buscfg;
    memset(&buscfg, 0, sizeof(buscfg));
    buscfg.mosi_io_num = mosi;
    buscfg.miso_io_num = miso;
    buscfg.sclk_io_num = sclk;
    buscfg.quadwp_io_num = -1;
    buscfg.quadhd_io_num = -1;
    buscfg.max_transfer_sz = 16000;
    buscfg.flags = 0;
    buscfg.intr_flags = 0;
    m_spi_host = spi_host;
    ESP_ERROR_CHECK(spi_bus_initialize(m_spi_host, &buscfg, SPI_DMA_CH_AUTO));
}

SPIDriver::~SPIDriver()
{
}

void SPIDriver::setClockSpeed(int speed)
{
    ESP_LOGI(TAG, "SPI clock speed = %d MHz", speed / 1000000);
    m_clock_speed_hz = speed;
}

void SPIDriver::addDevice(int cs)
{
    spi_device_interface_config_t devcfg;
    memset(&devcfg, 0, sizeof(devcfg));
    devcfg.clock_speed_hz = m_clock_speed_hz;
    devcfg.spics_io_num = cs;
    devcfg.queue_size = 7;
    devcfg.mode = 0;
    ESP_ERROR_CHECK(spi_bus_add_device(m_spi_host, &devcfg, &m_spi_dev));
}

bool SPIDriver::writeByte(const uint8_t *data, size_t length)
{
    spi_transaction_t trans;
    memset(&trans, 0, sizeof(spi_transaction_t));
    trans.length = length * 8;
    trans.tx_buffer = data;
    return spi_device_transmit(m_spi_dev, &trans) == ESP_OK;
}

bool SPIDriver::readByte(uint8_t *data, size_t length)
{
    spi_transaction_t trans;
    memset(&trans, 0, sizeof(spi_transaction_t));
    trans.length = length * 8;
    trans.flags = SPI_TRANS_USE_RXDATA;
    esp_err_t ret = spi_device_transmit(m_spi_dev, &trans);
    if (ret == ESP_OK) {
        memcpy(data, trans.rx_data, length);
        return true;
    }
    return false;
}
